package com.u2ds.dss.tools;


import com.alibaba.fastjson.JSONObject;
import com.u2ds.console.web.util.CourtStatusUtil;
import com.u2ds.console.web.util.TypeUtil;
import com.u2ds.core.entity.BaseEntity;
import com.u2ds.core.util.DateUtil;
import com.u2ds.dss.entity.court.CourtInfo;
import com.u2ds.dss.entity.court.CourtOrder;
import com.u2ds.dss.entity.court.CourtProduct;
import com.u2ds.dss.entity.court.CourtTimeRule;
import com.u2ds.dss.tools.util.TimeRule;

import java.io.UnsupportedEncodingException;
import java.util.*;

/**
 * Created by Ethan.Yuan on 2017/1/20.
 */
public class ProductGenerateTool {

    private static Double minUnit = 1d;

    /**
     * 生成指定场地的商品
     * @param timeRuleList
     * @param orderList
     * @return
     */
    public List<CourtProduct> generateProducts(JSONObject courtInfo, List<JSONObject> timeRuleList, List<JSONObject> orderList, Date workingDate){
        List<CourtProduct> productList = new LinkedList<CourtProduct>();
        Date orderStartTime = orderList.size() > 0 ? orderList.get(0).getTimestamp(CourtOrder.startTime) : workingDate;
        //遍历所有时间规则
        for(JSONObject timeRule : timeRuleList){
            Date workTime = this.getWorkingTime(workingDate, timeRule, true);
            Date endTime = this.getWorkingTime(workingDate, timeRule, false);
            while(workTime.before(endTime)){
                CourtProduct product = new CourtProduct();
                product.put("orderStartTime", orderStartTime);
                //先生成基础信息
                product.put(CourtProduct.courtId, courtInfo.get(CourtInfo.id));
                product.put(CourtProduct.startTime, workTime);
                //将工作时间后移
                workTime = DateUtil.addHours(workTime, minUnit * timeRule.getDouble(CourtTimeRule.rate));
                product.put(CourtProduct.endTime, workTime);
                productList.addAll(this.generateSubProducts(product, orderList));
                orderStartTime = product.getTimestamp("orderStartTime");
            }
        }
        return productList;

    }

    private Date getWorkingTime(Date date, JSONObject timeRule, Boolean isStart){
        Integer targetHour = timeRule.getInteger(isStart ? CourtTimeRule.startHour : CourtTimeRule.endHour);
        Integer targetMinute = timeRule.getInteger(isStart ? CourtTimeRule.startMinute: CourtTimeRule.endMinute);
        Calendar c = Calendar.getInstance();
        c.set(Calendar.HOUR_OF_DAY, targetHour);
        c.set(Calendar.MINUTE, targetMinute == null ? 0 : targetMinute);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
        return c.getTime();
    }

    /**
     * 对于已经检查过的order，不再重复检查
     * 某个product，若和order有时间交叉的，需进行拆分
     * @param product
     * @param orderList
     * @return
     */
    private List<CourtProduct> generateSubProducts(CourtProduct product, List<JSONObject> orderList){
        List<CourtProduct> subProductList = new ArrayList<CourtProduct>();
        int orderIndex = product.getIntValue("orderIndex");
        while(orderIndex < orderList.size()){
            JSONObject courtOrder = orderList.get(orderIndex);
            int relation = this.poRelation(product, courtOrder);
            if(relation == -1){
                subProductList.add(product);
                break;
            }else if(relation == 1){
                CourtProduct indexProduct = product;
                List<CourtProduct> splitProducts = this.splitProduct(indexProduct, courtOrder, relation);
//                indexProduct =
                //拆分后的product有可能和后面的order继续相交，但只可能是最后一个product
                subProductList.addAll(splitProducts.subList(0, splitProducts.size() > 2? splitProducts.size() - 1 : 1));
                indexProduct = splitProducts.get(splitProducts.size() - 1);
            }
        }
        return subProductList;
    }


    private List<CourtProduct> splitProduct(CourtProduct product, JSONObject order, int relation){
        List<CourtProduct> subProducts = new ArrayList<CourtProduct>();
        if(relation == 0){
            product.put(CourtProduct.status, CourtStatusUtil.COURT_AVAILABLE);
            subProducts.add(product);
        }else if(relation == 1){
            this.pushProductByTime(product.getTimestamp(CourtProduct.startTime), order.getTimestamp(CourtOrder.startTime), CourtStatusUtil.COURT_AVAILABLE, product, subProducts);
            this.pushProductByTime(order.getTimestamp(CourtOrder.startTime), order.getTimestamp(CourtOrder.endTime), CourtStatusUtil.COURT_BOOKED, product, subProducts);
            this.pushProductByTime(order.getTimestamp(CourtOrder.endTime), product.getTimestamp(CourtProduct.endTime), CourtStatusUtil.COURT_AVAILABLE, product, subProducts);
        }else if(relation == 2){
            product.put(CourtProduct.status, CourtStatusUtil.COURT_BOOKED);
            subProducts.add(product);
        }else if(relation == 3){
            this.pushProductByTime(product.getTimestamp(CourtOrder.startTime), order.getTimestamp(CourtOrder.startTime), CourtStatusUtil.COURT_BOOKED, product, subProducts);
            this.pushProductByTime(order.getTimestamp(CourtOrder.startTime), product.getTimestamp(CourtOrder.endTime), CourtStatusUtil.COURT_AVAILABLE, product, subProducts);
        }else if(relation == 4){
            this.pushProductByTime(product.getTimestamp(CourtOrder.startTime), order.getTimestamp(CourtOrder.endTime), CourtStatusUtil.COURT_BOOKED, product, subProducts);
            this.pushProductByTime(order.getTimestamp(CourtOrder.endTime), product.getTimestamp(CourtOrder.endTime), CourtStatusUtil.COURT_AVAILABLE, product, subProducts);
        }
        return subProducts;
    }

    private void pushProductByTime(Date startTime, Date endTime, Integer status, CourtProduct product, List<CourtProduct> subProducts){
        if(DateUtil.getDiffHours(startTime, endTime) >= minUnit){
            CourtProduct product1 = new CourtProduct();
            product.clone(product1);
            product1.put(CourtProduct.startTime, startTime);
            product1.put(CourtProduct.endTime, endTime);
            product1.put(CourtProduct.status, status);
            subProducts.add(product1);
        }
    }


    /**
     * product和order之间的关系
     * -1:不相交，product在order前面;0：不相交, order在product后面；1：product包含order；2：order包含product；3：product和order相交，product在order之前；4：product和order相交，order在product之前
     * 若时间点有重合的，以order的时间为范围较大的时间，比如：order与product
     * @param product
     * @param order
     * @return
     */
    private int poRelation(CourtProduct product, JSONObject order){
        if(!product.getTimestamp(CourtProduct.endTime).after(order.getTimestamp(CourtOrder.startTime))){
            return -1;
        }else if(!product.getTimestamp(CourtProduct.startTime).before(order.getTimestamp(CourtOrder.endTime))){
            return 0;
        } else if(!(product.getTimestamp(CourtProduct.startTime).after(order.getTimestamp(CourtOrder.startTime)))
                && !(product.getTimestamp(CourtProduct.endTime).before(order.getTimestamp(CourtOrder.endTime)))
                && !(product.getTimestamp(CourtProduct.startTime).equals(order.getTimestamp(CourtOrder.startTime)) && product.getTimestamp(CourtProduct.endTime).equals(order.getTimestamp(CourtOrder.endTime)))){
            return 1;
        }else if((!order.getTimestamp(CourtProduct.startTime).after(product.getTimestamp(CourtOrder.startTime)))
                && (!order.getTimestamp(CourtProduct.endTime).before(product.getTimestamp(CourtOrder.endTime)))){
            return 2;
        }else if(product.getTimestamp(CourtProduct.endTime).after(order.getTimestamp(CourtOrder.startTime))
                && !(product.getTimestamp(CourtOrder.endTime).after(order.getTimestamp(CourtOrder.endTime)))){
            return 3;
        }else if(order.getTimestamp(CourtProduct.endTime).after(product.getTimestamp(CourtOrder.startTime))
                && !(order.getTimestamp(CourtOrder.endTime).after(product.getTimestamp(CourtOrder.endTime)))){
            return 4;
        }else{
            return 0;
        }


    }

}
